import { App } from 'vue'
import { toFixed } from './tool'

interface EventData {
  id?: string
  type?: string
  data?: any
  pageId?: string
  uid?: string
}

/**
 * @description 神策埋点对象
 */
export const Sensors = {
  track(event: string, data: any) {
    const { sensors } = window
    if (sensors) {
      sensors.track(event, data)
    }
  },
  pageError(data?: Partial<EventData>) { // 页面错误统计使用
    this.track('H5PageError', {
      h5_event_id: data?.id,
      h5_event_type: data?.type,
      h5_page_id: data?.pageId,
      h5_custom_data: JSON.stringify(data?.data || {})
    })
  },
  bizEvent(data?: Partial<EventData>) { // 业务事件统计
    this.track('H5BizEvent', {
      h5_event_id: data?.id,
      h5_event_type: data?.type,
      h5_page_id: data?.pageId,
      uid: data?.uid,
      h5_custom_data: JSON.stringify(data?.data || {})
    })
  },
  collectLog(data?: Partial<EventData>) { // 程序日志事务统计
    this.track('H5CollectLog', {
      h5_event_id: data?.id,
      h5_event_type: data?.type,
      h5_page_id: data?.pageId,
      uid: data?.uid,
      h5_custom_data: JSON.stringify(data?.data || {})
    })
  },
  pageLoadedFinished(isOnload = true, pageId?: string) {
    const currentTime = new Date().getTime()
    const { pageLoadStartTime } = window
    let str = ''
    const { performance } = window
    if(performance && performance.timing) {
      const { domLoading, fetchStart, domComplete, domInteractive } = performance.timing
      // 如果是window.onload调用埋点时间，则使用domComplete时间，否则使用当前时间
      const domComp = isOnload ? domComplete : currentTime
      str = `白屏时间：${toFixed((domLoading - fetchStart)/1000, 2)}s; 解析dom树耗时：${toFixed((domComp - domInteractive)/1000, 2)}s;`
    }
    this.track('H5PageLoadFinished', {
      page_loaded_duration: toFixed((currentTime - pageLoadStartTime) / 1000, 2),
      h5_event_id: 'page_loaded_duration',
      h5_event_type: 'page_loaded',
      h5_page_id: pageId,
      h5_custom_data: str
    })
  },
  windowError(message: any, source: any, lineno: any, colno: any) {
    this.pageError({
      id: 'page_error_window',
      type: 'window',
      data: { message, source, lineno, colno }
    })
  },
  vueError(error: any, vm: any, info: any) {
    this.pageError({
      id: 'page_error_vue',
      type: 'vue',
      data: { error: error.message, info, componentTag: vm.$options._componentTag }
    })
  }
}

/**
 * @description 设置神策埋点属性
 * 所有参数默认为 true
 * @param { boolean } isPageLoadedDuration 是否需要加载时长埋点
 * @param { boolean } isWindowOnerror 是否需要window.onerror错误埋点
 * @param { boolean } isVueErrorHandler 是否需要vue errorHandler错误埋点
 */
export interface SetupSensorsOptions {
  isPageLoadedDuration?: boolean
  isWindowOnerror?: boolean
  isVueErrorHandler?: boolean
}

/**
 * @description 神策埋点数据初始化
 * 1. 页面加载时长埋点
 * 2. window错误监听埋点
 * 3. vue内部错误埋点
 * @param app { object } vue对象
 * @param options { undefined | object }
 */
export function setupSensors(app: App, options: SetupSensorsOptions = {}) {
  if(process.env.APP_ENV !== 'production') return
  const { isPageLoadedDuration = true, isWindowOnerror = true, isVueErrorHandler = true } = options
  if (isPageLoadedDuration) {
    // 页面加载时长埋点
    window.addEventListener('load', () => {
      Sensors.pageLoadedFinished()
    })
  }
  if (isWindowOnerror) {
    // window错误监听埋点
    window.onerror = (message, source, lineno, colno) => {
      Sensors.windowError(message, source, lineno, colno)
    }
  }
  if (isVueErrorHandler) {
    // vue内部错误埋点
    app.config.errorHandler = (error, vm, info) => {
      Sensors.vueError(error, vm, info)
    }
  }
}
